/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * tameshi
 * Copyright (C) Massimiliano Maniscalco 2012 <massi.neptune@yahoo.com>
 * 
tameshi is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * tameshi is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _CONTROLLER_H_
#define _CONTROLLER_H_

#include <gtkmm.h>
#include <giomm/file.h>
#include <fstream>
#include <list>
#include "domanda.h"
#include "domande_list_model.h"
#include "popup_button_model.h"

#define STATUS_STARTING		0
#define STATUS_LOADING		1
#define STATUS_RUNNING		2

class Domanda;
class TestEngine;

using namespace std;

class Controller
{
public:
	inline Controller ()
	{}
	inline Controller( Glib::RefPtr<Gtk::Builder> _bldr, Glib::RefPtr<Gtk::Application> _app );
	inline ~Controller ();
	inline Gtk::Window* get_main_window ( void ) { return _mainWin; }
	bool save_data ( const Glib::ustring &filename );
	inline bool should_save ( void ) { return _shouldSaveDomande; }
	inline Glib::ustring data_path ( void ) { return _dataPath; }

protected:
	void load_data ( const Glib::ustring &filename );
	bool load_items_from_xml_file ( const Glib::ustring &filename );
	template <class ItemClass>
	int save_items_to_xml_file ( list<ItemClass> &_itemsList, ofstream *xmlstr );
	void connect_signals ( void );
	void on_cancel_button_clicked ( Gtk::Window *win );
	// main win
	bool on_main_win_focus_in ( GdkEventFocus *event );
	bool on_main_win_focus_out ( GdkEventFocus *event );
	void on_items_tree_selection_changed ( void );
	void get_tree_row_ref ( const vector<Gtk::TreePath> &_sel, Glib::RefPtr<Gtk::TreeModel> _listModel, vector<Gtk::TreeRowReference> &_selRef );
	list<Domanda>::iterator get_domanda_iterator ( Gtk::TreeModel::Row _row );
	void load_pop_up_button ( vector<Glib::ustring>::iterator _start, vector<Glib::ustring>::iterator _end, Glib::RefPtr<Gtk::ListStore> _popUpList );
	// main toolbar and menu
	void on_save_action_clicked ( void );
	void on_import_action_clicked ( void );
	void on_quit_menu_selected ( void );
	void on_add_action_clicked ( void );
	void on_remove_action_clicked ( void );
	void on_edit_action_clicked ( void );
	void on_info_action_clicked ( void );
	void on_reset_action_clicked ( void );
	void on_search_duplicati_action_clicked ( const Gtk::Widget *sender );
	void on_search_action_clicked ( void );
	void on_test_action_clicked ( void );
	void on_quick_search_icon_clicked ( Gtk::EntryIconPosition icon_position, const GdkEventButton* event);
	void on_quick_search_text_inserted ( guint position, const gchar* chars, guint n_chars );
	void on_quick_search_text_deleted ( guint position, guint n_chars );
	void on_quick_search_menu_toggled ( Gtk::RadioMenuItem *sender );
	void on_about_action_clicked ( void );
	void on_about_response ( int response_id, Gtk::AboutDialog *_about );
	// domande tree view
	void load_domande_in_tree_view ( void );
	void domande_tree_remove_selected_rows ( const vector<Gtk::TreePath> &_sel );
	void on_domande_tree_double_clicked ( GdkEventButton *event );
	// compare domande
	unsigned short compare_words_set ( set<Glib::ustring> *modelSet, set<Glib::ustring> *otherSet );
	// import
	void import_select_file ( void );
	void import_text_file ( const Glib::ustring &filetxt, const Glib::ustring &separatore );
	bool try_get_next_string ( ifstream &infile, Domanda *temp, string &textline, const string &next, size_t *start_pos, Glib::ustring &segmento );
	bool get_next_string ( const string &textline, const string &next, size_t *start_pos, Glib::ustring &segmento );
	// edit window
	inline void add_bold_tag ( Glib::RefPtr<Gtk::TextBuffer> txtbfr );
	inline void add_underline_tag ( Glib::RefPtr<Gtk::TextBuffer> txtbfr );
	inline void add_superscript_tag ( Glib::RefPtr<Gtk::TextBuffer> txtbfr );
	inline void add_highlight_tag ( Glib::RefPtr<Gtk::TextBuffer> txtbfr );
	void populate_edit_window ( const Domanda &quaestio );
	void on_edit_tag_apply ( const Glib::ustring &tagName );
	void on_edit_erase_tag ( void );
	void on_edit_conferma_button_clicked ( void );
	// info window
	void on_previous_info_item_action ( void );
	void on_next_info_item_action ( void );
	// search window
	void on_search_conferma_button_clicked ( void );
	void on_search_default_button_clicked ( void );
	// test options window
	void on_test_opt_inizia_button_clicked ( void );
	void prepara_selezione_domande ( list<Domanda> *_selezionate );
	void on_signal_domande_changed ( const Domanda &quaestio );
	void on_signal_domanda_edit ( const Domanda &quaestio );
	void on_test_win_closed ( void );
	// xml parser
	void on_signal_domanda_loaded ( const Domanda &quaestio );
	void on_signal_import_end ( void );

private:
	Glib::RefPtr<Gtk::Application> _mainApp;
	Glib::RefPtr<Gtk::Builder> _builder;
	char _startingApp;
	list<Domanda> *_domande;
	unsigned int _domandeCaricate;
	bool _shouldSaveDomande;
	Glib::ustring _dataPath;
	typedef pair<unsigned short,unsigned short> comp_data;
	typedef pair<Domanda *,comp_data> comparativa;
	Gtk::Window *_mainWin;
	Gtk::Statusbar *_mainStatusbar;
	int _stsbarItemSelId;
	int _stsbarItemDiskId;
	PopUpButtonModel* _buttonPopUpColumn;
	vector<Glib::ustring> *_correttaPopUpStrings;
	TestEngine *_testCtrl;
	// main menu
	Gtk::MenuBar *_mainMenuBar;
	Gtk::MenuItem *_importMenuitem;
	Gtk::ImageMenuItem *_saveMenuitem;
	Gtk::ImageMenuItem *_quitMenuitem;
	Gtk::MenuItem *_newMenuitem;
	Gtk::MenuItem *_remMenuitem;
	Gtk::MenuItem *_editMenuitem;
	Gtk::MenuItem *_resetMenuitem;
	Gtk::MenuItem *_infoMenuitem;
	Gtk::CheckMenuItem *_duplicatiMenuitem;
	Gtk::MenuItem *_aboutMenuitem;
	// main toolbar
	Gtk::Toolbar *_mainToolbar;
	Gtk::ToolButton *_saveToolButton;
	Gtk::ToolButton *_importToolButton;
	Gtk::ToolButton *_addToolButton;
	Gtk::ToolButton *_remToolButton;
	Gtk::ToolButton *_editToolButton;
	Gtk::ToolButton *_infoToolButton;
	Gtk::ToolButton *_resetToolButton;
	Gtk::ToggleToolButton *_duplicatiToolButton;
	Gtk::ToggleToolButton *_searchToolButton;
	Gtk::ToolButton *_testToolButton;
	Gtk::Entry *_quickSearchEntry;
	Gtk::Menu *_quickSearchMenu;
	Gtk::RadioMenuItem *_quickSearchAllMenuItem;
	Gtk::RadioMenuItem *_quickSearchCodiceMenuItem;
	Gtk::RadioMenuItem *_quickSearchDomandaMenuItem;
	Gtk::RadioMenuItem *_quickSearchArgomentoMenuItem;
	// domande tree view
	DomandeListModel* _domandeListColumns;
	Glib::RefPtr<Gtk::ListStore> _domandeListStore;
	Gtk::TreeView* _domandeListView;
	Glib::RefPtr<Gtk::TreeSelection> _domandeListSelection;
	// import options
	Gtk::Window *_importWin;
	Gtk::Button *_importButton;
	Gtk::Entry *_importSepEntry;
	// edit window
	Gtk::Window *_editWin;
	Gtk::ToolButton *_editBoldToolButton;
	Gtk::ToolButton *_editUnderlineToolButton;
	Gtk::ToolButton *_editSuperscriptToolButton;
	Gtk::ToolButton *_editHighlightToolButton;
	Gtk::ToolButton *_editEraseToolButton;
	Gtk::Entry *_editCodiceEntry;
	Gtk::Entry *_editArgomentoEntry;
	Gtk::TextView *_editDomandaTxtView;
	Gtk::TextView *_editRispATxtView;
	Gtk::TextView *_editRispBTxtView;
	Gtk::TextView *_editRispCTxtView;
	Gtk::TextView *_editRispDTxtView;
	Gtk::TextView *_editAppuntiTxtView;
	Glib::RefPtr<Gtk::TextBuffer> _editDomandaTxtBfr;
	Glib::RefPtr<Gtk::TextBuffer> _editRispATxtBfr;
	Glib::RefPtr<Gtk::TextBuffer> _editRispBTxtBfr;
	Glib::RefPtr<Gtk::TextBuffer> _editRispCTxtBfr;
	Glib::RefPtr<Gtk::TextBuffer> _editRispDTxtBfr;
	Glib::RefPtr<Gtk::TextBuffer> _editAppuntiTxtBfr;
	Glib::RefPtr<Gtk::ListStore> _correttaPopUpStore;
	Gtk::ComboBox *_editCorrettaCombobox;
	Gtk::Button *_editConfermaButton;
	Gtk::Button *_editAnnullaButton;
	// info window
	Gtk::Window *_infoWin;
	Gtk::ToolButton *infoPreviousButton;
	Gtk::ToolButton *infoNextButton;
	Gtk::Entry *_infoRisposteEntry;
	Gtk::Entry *_infoCorretteEntry;
	Gtk::Entry *_infoProbabilitaEntry;
	Gtk::Label *_infoUltimaLabel;
	Gtk::Entry *_infoTempoTotaleEntry;
	Gtk::Entry *_infoTempoMedioEntry;
	Gtk::Entry *_infoUltimoTempoEntry;
	// search window
	Gtk::Window *_searchWin;
	Gtk::Entry *_searchCodiceEntry;
	Gtk::Entry *_searchDomandaEntry;
	Gtk::Entry *_searchArgomentoEntry;
	Gtk::Button *_searchDefaultButton;
	Gtk::Button *_searchConfermaButton;
	// test options window
	Gtk::Window *_testOptWin;
	Gtk::Entry *_testOptCodiceEntry;
	Gtk::Entry *_testOptArgomentoEntry;
	Gtk::Scale *_testOptPercentScale;
	Gtk::Button *_testOptAnnullaButton;
	Gtk::Button *_testOptIniziaButton;
	// test window
	Gtk::Window *_testWin;
	sigc::connection _testQuaestioEditConnection;
	sigc::connection _testQuaestioChangedConnection;
	sigc::connection _testWinClosedConnection;
	// error log window
	Gtk::Window *error_log_win;
	Gtk::TextView *error_log_textview;
	Glib::RefPtr<Gtk::TextBuffer> error_log_textbuffer;
	
};

inline Controller::
Controller( Glib::RefPtr<Gtk::Builder> _bldr, Glib::RefPtr<Gtk::Application> _app ) :
	_startingApp ( STATUS_STARTING ), _shouldSaveDomande ( false ), _builder ( _bldr ), _mainApp ( _app )
{
	_domande = new list<Domanda>;
	Glib::RefPtr<Gio::File> tameshiDir = Gio::File::create_for_path ( Glib::get_home_dir () + Glib::ustring ( "/.tameshi" ) );
	if ( !tameshiDir->query_exists () )
		tameshiDir->make_directory ();
	_dataPath = tameshiDir->get_path() + Glib::ustring ( "/tameshi_quiz.xml" );
	_bldr->get_widget("main_window", _mainWin);
	_domandeListColumns = new DomandeListModel ();
	_bldr->get_widget ("main_statusbar", _mainStatusbar);
	_stsbarItemSelId = _mainStatusbar->get_context_id ( Glib::ustring ( "ITEM_SEL" ) );
	_stsbarItemDiskId = _mainStatusbar->get_context_id ( Glib::ustring ( "ITEM_DISK" ) );
	_buttonPopUpColumn = new PopUpButtonModel ();
	Glib::ustring _risp[4] = { "a", "b", "c", "d" };
	_correttaPopUpStrings = new vector<Glib::ustring> ( _risp, _risp + 4 );
	// main menu
	_bldr->get_widget ("main_menubar", _mainMenuBar);
	_bldr->get_widget ("import_menuitem", _importMenuitem);
	_bldr->get_widget ("save_menuitem", _saveMenuitem);
	_bldr->get_widget ("quit_menuitem", _quitMenuitem);
	_bldr->get_widget ("new_menuitem", _newMenuitem);
	_bldr->get_widget ("remove_menuitem", _remMenuitem);
	_bldr->get_widget ("edit_menuitem", _editMenuitem);
	_bldr->get_widget ("reset_menuitem", _resetMenuitem);
	_bldr->get_widget ("info_menuitem", _infoMenuitem);
	_bldr->get_widget ("duplicati_menuitem", _duplicatiMenuitem);
	_bldr->get_widget ("about_menuitem", _aboutMenuitem);
	// main toolbar
	_bldr->get_widget ("main_toolbar", _mainToolbar);
	_bldr->get_widget ("save_toolbutton", _saveToolButton);
	_bldr->get_widget ("import_toolbutton", _importToolButton);
	_bldr->get_widget ("add_toolbutton", _addToolButton);
	_bldr->get_widget ("remove_toolbutton", _remToolButton);
	_bldr->get_widget ("edit_toolbutton", _editToolButton);
	_bldr->get_widget ("info_toolbutton", _infoToolButton);
	_bldr->get_widget ("reset_toolbutton", _resetToolButton);
	_bldr->get_widget ("duplicati_toolbutton", _duplicatiToolButton);
	_bldr->get_widget ("search_toolbutton", _searchToolButton);
	_bldr->get_widget ("test_toolbutton", _testToolButton);
	_bldr->get_widget ("qsearch_entry", _quickSearchEntry);
	_quickSearchEntry->set_icon_from_stock ( Gtk::StockID ("gtk-find"), Gtk::ENTRY_ICON_PRIMARY );
	// quick search menu
	_bldr->get_widget ("qsearch_menu", _quickSearchMenu);
	_bldr->get_widget ("qsearch_all_menuitem", _quickSearchAllMenuItem);
	_bldr->get_widget ("qsearch_codice_menuitem", _quickSearchCodiceMenuItem);
	_bldr->get_widget ("qsearch_domanda_menuitem", _quickSearchDomandaMenuItem);
	_bldr->get_widget ("qsearch_argomento_menuitem", _quickSearchArgomentoMenuItem);
	// domande treeview
	_domandeListStore = Gtk::ListStore::create(*_domandeListColumns);
	_bldr->get_widget ("main_treeview", _domandeListView);
	_domandeListView->set_model(_domandeListStore);
	_domandeListSelection = _domandeListView->get_selection ();
	_domandeListSelection->set_mode (Gtk::SELECTION_MULTIPLE);
	// import options
	_bldr->get_widget ("import_window", _importWin);
	_bldr->get_widget ("import_button", _importButton);
	_bldr->get_widget ("import_string_entry", _importSepEntry);
	// edit window
	_bldr->get_widget ("edit_window", _editWin);
	_bldr->get_widget ("edit_bold_toolbutton", _editBoldToolButton);
	_bldr->get_widget ("edit_underline_toolbutton", _editUnderlineToolButton);
	_bldr->get_widget ("edit_superscript_toolbutton", _editSuperscriptToolButton);
	_bldr->get_widget ("edit_highlight_toolbutton", _editHighlightToolButton);
	_bldr->get_widget ("edit_erase_toolbutton", _editEraseToolButton);
	_bldr->get_widget ("edit_codice_entry", _editCodiceEntry);
	_bldr->get_widget ("edit_argomento_entry", _editArgomentoEntry);
	_bldr->get_widget ("edit_domanda_textview", _editDomandaTxtView);
	_bldr->get_widget ("edit_a_textview", _editRispATxtView);
	_bldr->get_widget ("edit_b_textview", _editRispBTxtView);
	_bldr->get_widget ("edit_c_textview", _editRispCTxtView);
	_bldr->get_widget ("edit_d_textview", _editRispDTxtView);
	_bldr->get_widget ("edit_appunti_textview", _editAppuntiTxtView);
	_editDomandaTxtBfr = _editDomandaTxtView->get_buffer ();
	add_bold_tag ( _editDomandaTxtBfr );
	add_underline_tag ( _editDomandaTxtBfr );
	add_superscript_tag ( _editDomandaTxtBfr );
	add_highlight_tag ( _editDomandaTxtBfr );
	_editRispATxtBfr = _editRispATxtView->get_buffer ();
	add_bold_tag ( _editRispATxtBfr );
	add_underline_tag ( _editRispATxtBfr );
	add_superscript_tag ( _editRispATxtBfr );
	add_highlight_tag ( _editRispATxtBfr );
	_editRispBTxtBfr = _editRispBTxtView->get_buffer ();
	add_bold_tag ( _editRispBTxtBfr );
	add_underline_tag ( _editRispBTxtBfr );
	add_superscript_tag ( _editRispBTxtBfr );
	add_highlight_tag ( _editRispBTxtBfr );
	_editRispCTxtBfr = _editRispCTxtView->get_buffer ();
	add_bold_tag ( _editRispCTxtBfr );
	add_underline_tag ( _editRispCTxtBfr );
	add_superscript_tag ( _editRispCTxtBfr );
	add_highlight_tag ( _editRispCTxtBfr );
	_editRispDTxtBfr = _editRispDTxtView->get_buffer ();
	add_bold_tag ( _editRispDTxtBfr );
	add_underline_tag ( _editRispDTxtBfr );
	add_superscript_tag ( _editRispDTxtBfr );
	add_highlight_tag ( _editRispDTxtBfr );
	_editAppuntiTxtBfr = _editAppuntiTxtView->get_buffer ();
	add_bold_tag ( _editAppuntiTxtBfr );
	add_underline_tag ( _editAppuntiTxtBfr );
	add_superscript_tag ( _editAppuntiTxtBfr );
	add_highlight_tag ( _editAppuntiTxtBfr );
	_correttaPopUpStore = Gtk::ListStore::create(*_buttonPopUpColumn);
	_bldr->get_widget ("edit_combobox", _editCorrettaCombobox);
	_editCorrettaCombobox->set_model(_correttaPopUpStore);
	load_pop_up_button ( _correttaPopUpStrings->begin(), _correttaPopUpStrings->end(), _correttaPopUpStore );
	_bldr->get_widget ("edit_conferma_button", _editConfermaButton);
	_bldr->get_widget ("edit_annulla_button", _editAnnullaButton);
	// info window
	_bldr->get_widget ("info_window", _infoWin);
	_bldr->get_widget ("previous_info_toolbutton", infoPreviousButton);
	_bldr->get_widget ("next_info_toolbutton", infoNextButton);
	_bldr->get_widget ("info_entry1", _infoRisposteEntry);
	_bldr->get_widget ("info_entry2", _infoCorretteEntry);
	_bldr->get_widget ("info_entry3", _infoProbabilitaEntry);
	_bldr->get_widget ("info_label6", _infoUltimaLabel);
	_bldr->get_widget ("info_entry4", _infoTempoTotaleEntry);
	_bldr->get_widget ("info_entry5", _infoTempoMedioEntry);
	_bldr->get_widget ("info_entry6", _infoUltimoTempoEntry);
	// search window
	_bldr->get_widget ("search_window", _searchWin);
	_searchWin->set_transient_for ( *_mainWin );
	_bldr->get_widget ("search_codice_entry", _searchCodiceEntry);
	_bldr->get_widget ("search_domanda_entry", _searchDomandaEntry);
	_bldr->get_widget ("search_argomento_entry", _searchArgomentoEntry);
	_bldr->get_widget ("search_default_button", _searchDefaultButton);
	_bldr->get_widget ("search_conferma_button", _searchConfermaButton);
	// test options window
	_bldr->get_widget ("test_options_window", _testOptWin);
	_bldr->get_widget ("test_opt_codice_entry", _testOptCodiceEntry);
	_bldr->get_widget ("test_opt_argomento_entry", _testOptArgomentoEntry);
	_bldr->get_widget ("test_opt_scale", _testOptPercentScale);
	_bldr->get_widget ("test_opt_annulla_button", _testOptAnnullaButton);
	_bldr->get_widget ("test_opt_inizia_button", _testOptIniziaButton);
	// test window
	_bldr->get_widget ("test_scmult_window", _testWin);
	// error log window
	_bldr->get_widget ("error_log_window", error_log_win);
	_bldr->get_widget ("error_log_textview", error_log_textview);
	error_log_textbuffer = error_log_textview->get_buffer ();
	
	connect_signals ();
}

inline Controller::
~Controller ()
{
	delete _domandeListColumns;
	delete _buttonPopUpColumn;
	delete _correttaPopUpStrings;
	delete _domande;
}

inline void Controller::
add_bold_tag ( Glib::RefPtr<Gtk::TextBuffer> txtbfr )
{
	Glib::RefPtr<Gtk::TextTag> boldTag = txtbfr->create_tag ( "bold" );
	boldTag->set_property("weight", Pango::WEIGHT_BOLD);
}

inline void Controller::
add_underline_tag ( Glib::RefPtr<Gtk::TextBuffer> txtbfr )
{
	Glib::RefPtr<Gtk::TextTag> underlineTag = txtbfr->create_tag ( "underline" );
	underlineTag->set_property("underline", Pango::UNDERLINE_SINGLE);
}

inline void Controller::
add_superscript_tag ( Glib::RefPtr<Gtk::TextBuffer> txtbfr )
{
	Glib::RefPtr<Gtk::TextTag> superscriptTag = txtbfr->create_tag ( "superscript" );
	superscriptTag->set_property ("rise", 10 * Pango::SCALE);
	superscriptTag->set_property ("size", 8 * Pango::SCALE);
}

inline void Controller::
add_highlight_tag ( Glib::RefPtr<Gtk::TextBuffer> txtbfr )
{
	Glib::RefPtr<Gtk::TextTag> highlightTag = txtbfr->create_tag ( "highlight" );
	highlightTag->set_property("weight", Pango::WEIGHT_BOLD);
	highlightTag->set_property ("foreground", Glib::ustring ( "blue" ) );
	highlightTag->set_property ("background", Glib::ustring ( "yellow" ) );
}

#endif // _CONTROLLER_H_
